﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using JEdwonTune.Lib;
using JEdwonTune.Lib.Hibernate;
using System.Xml;
using System.IO;

namespace JEdwonTune.Hibernate {
    public partial class FrmMappingBuilder : Form {
        public FrmMappingBuilder() {
            InitializeComponent();
        }

        private String _TableName;
        public String TableName {
            set { _TableName = value; }
            get { return _TableName; }
        }

        private int _TableType;
        public int TableType {
            set { _TableType = value; }
            get { return _TableType; }
        }
        private String _Pk;
        public String Pk {
            set { _Pk = value; }
            get { return _Pk; }
        }
        private IList<ColumnEO> _ColumnList;
        public IList<ColumnEO> ColumnList {
            set { _ColumnList = value; }
            get { return _ColumnList; }
        }
        private String _EOName;

        private void btnCancel_Click(object sender, EventArgs e) {
            this.Close();
        }

        private void FrmMappingBuilder_Load(object sender, EventArgs e) {
            this.gvColumns.AutoGenerateColumns = false;
            try
            {
                DbUtil.ParseDataType();
            }
            catch(Exception ex) {
                MessageBox.Show(ex.Message, "初始化Mapping生成器错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Close();
                return;
            }
            Init();
        }

        private void Init() {
            this.txtEOName.Text = _EOName = MyUtil.ParseName2EOStyle(_TableName)+"EO";

            this.gvColumns.DataSource = _ColumnList;

            this.cbxGenerator.DataSource = Ctrls.IDGenerator();
            this.cbxGenerator.DisplayMember = "Text";
            this.cbxGenerator.ValueMember = "Value";

            this.cbxPolymorphism.DataSource = Ctrls.PolymorphismList();
            this.cbxPolymorphism.DisplayMember = "Text";
            this.cbxPolymorphism.ValueMember = "Value";

            this.txtTableName.Text = _TableName;
            this.cbDynamicInsert.Checked = true;
            this.cbDynamicUpdate.Checked = true;

            IList<KeyValuePair<String, String>> cols = new List<KeyValuePair<String, String>>();
            cols.Add(new KeyValuePair<String,String>("",""));
            foreach (ColumnEO eo in _ColumnList) {
                cols.Add(new KeyValuePair<String, String>(eo.Name, eo.Name));
            }
            this.cbxPK.DataSource = cols;
            this.cbxPK.DisplayMember = "Key";
            this.cbxPK.ValueMember = "Value";
            if(!String.IsNullOrEmpty(_Pk))
                this.cbxPK.SelectedValue = _Pk;

            if (!String.IsNullOrEmpty(MySess.Mapping.Assembly)) {
                this.txtAssembly.Text = MySess.Mapping.Assembly;
            }
            if (!String.IsNullOrEmpty(MySess.Mapping.Namespace)) {
                this.txtNamespace.Text = MySess.Mapping.Namespace;
            }

            this.cbb_Encode.ValueMember = "Key";
            this.cbb_Encode.DisplayMember = "Value";
            this.cbb_Encode.Items.Add(new KeyValuePair<String, String>("utf-8", "UTF-8"));
            this.cbb_Encode.Items.Add(new KeyValuePair<String, String>("gbk", "GBK"));
            this.cbb_Encode.Items.Add(new KeyValuePair<String, String>("gb2312", "GB2312"));
            this.cbb_Encode.Items.Add(new KeyValuePair<String, String>("ascii", "ASCII"));
            this.cbb_Encode.SelectedIndex = 0;
        }
        /// <summary>
        /// 构造一个属性的cs代码
        /// </summary>
        /// <param name="columnName"></param>
        /// <param name="type"></param>
        /// <param name="name"></param>
        /// <param name="comment"></param>
        /// <returns></returns>
        private String GetPropertyClassCode(String columnName,String type, String name,String comment) {
            //私有定义
            String _code = "\n\t\tprivate " + type + " _" + name + ";\n";
            //注释
            _code += "\t\t/// <summary>\n"
                + "\t\t/// " + comment + "\n"
                + "\t\t/// </summary>\n";
            //序列化声明
            if (this.cbSerialization.Checked) {
                _code += "\t\t[PropertyAttribute(Column = \"" + columnName + "\", TypeType = typeof(" + type + "))]\n"
                + "\t\t[DataMember]\n";
            }
            //公共定义
            _code += "\t\tpublic " + type + " " + name + "{\n"
                + "\t\t\tset{ _" + name + " = value; }\n"
                + "\t\t\tget{ return _" + name + "; }\n"
                + "\t\t}\n";
            return _code;
        }
        private void btnBuild_Click(object sender, EventArgs e) {

            #region 输入校验
            if (String.IsNullOrEmpty(this.txtAssembly.Text.Trim())) {
                MessageBox.Show("请输入程序集", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.txtAssembly.Focus();
                return;
            }
            if (String.IsNullOrEmpty(this.txtEOName.Text.Trim())) {
                MessageBox.Show("请输入实体类名", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.txtEOName.Focus();
                return;
            }
            if (String.IsNullOrEmpty(this.txtNamespace.Text.Trim())) {
                MessageBox.Show("请输入命名空间", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.txtNamespace.Focus();
                return;
            }
            #endregion


            #region EO主体类和Mapping文件
            XmlDocument doc = new XmlDocument();
            XmlNamespaceManager xnm = new XmlNamespaceManager(new NameTable());
            xnm.AddNamespace("nh", "urn:nhibernate-mapping-2.2");
            doc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\" ?><hibernate-mapping><class /></hibernate-mapping>");
            XmlNode nClass = doc.SelectSingleNode("//class");
            XmlHelper.SetNodeAttrValue(nClass, doc.CreateAttribute("name"), this.txtNamespace.Text + "." + this.txtEOName.Text + "," + this.txtAssembly.Text);
            XmlHelper.SetNodeAttrValue(nClass, doc.CreateAttribute("table"), this.txtTableName.Text);
            XmlHelper.SetNodeAttrValue(nClass, doc.CreateAttribute("lazy"), this.cbLazy.Checked.ToString().ToLower());
            XmlHelper.SetNodeAttrValue(nClass, doc.CreateAttribute("dynamic-update"), this.cbDynamicUpdate.Checked.ToString().ToLower());
            XmlHelper.SetNodeAttrValue(nClass, doc.CreateAttribute("dynamic-insert"), this.cbDynamicInsert.Checked.ToString().ToLower());
            if (!String.IsNullOrEmpty(this.cbxPolymorphism.SelectedValue.ToString())) {
                XmlHelper.SetNodeAttrValue(nClass, doc.CreateAttribute("polymorphism"), this.cbxPolymorphism.SelectedValue.ToString());
            }
            StringBuilder sbEO = new StringBuilder();
            sbEO.Append("/**********************************************************\n");
            sbEO.Append("\t Entity Object Shadow\n");
            sbEO.Append("\t Code Generated By JEdwon Tune " + MyUtil.TuneBuildVersion + " \n");
            sbEO.Append("\t Copyright(C) 2010 EDWON.CN \n");
            sbEO.Append("\t anyrock@mending.cn\n");
            sbEO.Append("***********************************************************/\n\n");
            sbEO.Append("using System.Runtime.Serialization;\n");
            sbEO.Append("using NHibernate.Mapping.Attributes;\n");
            sbEO.Append("using System;\n\n");
            sbEO.Append("namespace " + this.txtNamespace.Text + " {\n");
            //可序列化的
            if (this.cbSerializable.Checked) {
                sbEO.Append("\t[Serializable]\n");
            }
            if (this.cbSerialization.Checked) {
                sbEO.Append("\t[Class(Table = \"" + this.txtTableName.Text + "\", Lazy = " + this.cbLazy.Checked.ToString().ToLower() + ", DynamicInsert = " + this.cbDynamicInsert.Checked.ToString().ToLower() + ", DynamicUpdate = " + this.cbDynamicUpdate.Checked.ToString().ToLower() + ")]\n");
                sbEO.Append("\t[DataContract]\n");
            }
            if (this.cb_Shadow.Checked) {//shadow 模式
                sbEO.Append("\tpublic class " + this.txtEOName.Text + "SD {\n");
            } else {
                sbEO.Append("\tpublic class " + this.txtEOName.Text + " {\n");
            }
            if (this.cbxPK.SelectedValue.ToString() != "") {
                XmlNode nID = doc.CreateElement("id");
                String pName = MyUtil.ParseName2EOStyle(this.cbxPK.SelectedValue.ToString());
                XmlHelper.SetNodeAttrValue(nID,doc.CreateAttribute("name"),pName);
                XmlNode nIDColumn = doc.CreateElement("column");
                XmlHelper.SetNodeAttrValue(nIDColumn, doc.CreateAttribute("name"), this.cbxPK.SelectedValue.ToString());
                XmlHelper.SetNodeAttrValue(nIDColumn, doc.CreateAttribute("not-null"), "true");
                nID.AppendChild(nIDColumn);
                if (!String.IsNullOrEmpty(this.cbxGenerator.SelectedValue.ToString())) {
                    XmlNode nGen = doc.CreateElement("generator");
                    XmlHelper.SetNodeAttrValue(nGen, doc.CreateAttribute("class"), this.cbxGenerator.SelectedValue.ToString());
                    nID.AppendChild(nGen);
                }
                
                nClass.AppendChild(nID);
                sbEO.Append(GetPropertyClassCode(this.cbxPK.SelectedValue.ToString(),"String", pName, "Primary  Key"));
            }

            IList<ColumnEO> list = (IList<ColumnEO>)this.gvColumns.DataSource;
            foreach (ColumnEO eo in list) {
                if (eo.Name == this.cbxPK.SelectedValue.ToString()) continue;
                XmlNode node = doc.CreateElement("property");
                XmlHelper.SetNodeAttrValue(node, doc.CreateAttribute("name"), eo.PropertyName);
                XmlHelper.SetNodeAttrValue(node, doc.CreateAttribute("column"), eo.Name);
                XmlHelper.SetNodeAttrValue(node, doc.CreateAttribute("type"), eo.PropertyType.Replace("?",""));
                XmlHelper.SetNodeAttrValue(node, doc.CreateAttribute("not-null"), (!eo.Nullable).ToString().ToLower());
                if (eo.Length > 1)
                    XmlHelper.SetNodeAttrValue(node, doc.CreateAttribute("length"), eo.Length.ToString());
                sbEO.Append(GetPropertyClassCode(eo.Name,eo.PropertyType, eo.PropertyName,eo.Comment));
                nClass.AppendChild(node);
            }
            sbEO.Append("\t}\n");//close namespace
            sbEO.Append("}\n");//close class
            #endregion

            #region Shadow类
            StringBuilder sbShadow = new StringBuilder();
            if (this.cb_Shadow.Checked) {//shadow 模式
                sbShadow.Append("/**********************************************************\n");
                sbShadow.Append("\t Entity Object Shadow\n");
                sbShadow.Append("\t Code Generated By JEdwon Tune " + MyUtil.TuneBuildVersion + " \n");
                sbShadow.Append("\t Copyright(C) 2010 EDWON.CN \n");
                sbShadow.Append("\t anyrock@mending.cn\n");
                sbShadow.Append("***********************************************************/\n\n");
                sbShadow.Append("using System.Runtime.Serialization;\n");
                sbShadow.Append("using NHibernate.Mapping.Attributes;\n");
                sbShadow.Append("using System;\n\n");
                sbShadow.Append("namespace " + this.txtNamespace.Text + " {\n");
                //可序列化的
                if (this.cbSerializable.Checked) {
                    sbShadow.Append("\t[Serializable]\n");
                }
                sbShadow.Append("\tpublic class " + this.txtEOName.Text + ":" + this.txtEOName.Text + "SD {}\n");
                sbShadow.Append("}\n");
            }
            #endregion

            #region 设置Mapping文件的命名空间
            XmlAttribute xa = doc.CreateAttribute("xmlns");
            xa.Value = "urn:nhibernate-mapping-2.2";
            doc.DocumentElement.Attributes.Append(xa);
            #endregion

            //打开最后一次打开的目录
            if (!String.IsNullOrEmpty(MySess.Mapping.LastSavePath)) {
                this.folderBrowserDialog1.SelectedPath = MySess.Mapping.LastSavePath;
            }
            
            DialogResult dr = this.folderBrowserDialog1.ShowDialog();
            if (dr == DialogResult.OK) {
                String filePath = folderBrowserDialog1.SelectedPath + "/" + this.txtEOName.Text + ".hbm.xml";
                if (!File.Exists(filePath)
                    || MessageBox.Show("映射文件["+this.txtEOName.Text+".hbm.Xml]已存在，是否要覆盖？", "确认", MessageBoxButtons.OKCancel) == DialogResult.OK) {
                    doc.Save(filePath);
                    doc = null;
                }

                KeyValuePair<String, String> encode = (KeyValuePair<String, String>)this.cbb_Encode.SelectedItem;
                if (this.cb_Shadow.Checked) {
                    filePath = folderBrowserDialog1.SelectedPath + "/" + this.txtEOName.Text + "SD.cs";
                    if (!File.Exists(filePath)
                        || MessageBox.Show("类Shadow文件[" + this.txtEOName.Text + "SD.cs]已存在，是否要覆盖？", "确认", MessageBoxButtons.OKCancel) == DialogResult.OK) {
                        File.Delete(filePath);
                        FileStream fs = File.OpenWrite(filePath);

                        byte[] data = Encoding.GetEncoding(encode.Key).GetBytes(sbEO.ToString());
                        fs.Write(data, 0, data.Length);
                        fs.Flush();
                        fs.Close();
                    }
                    filePath = folderBrowserDialog1.SelectedPath + "/" + this.txtEOName.Text + ".cs";
                    if (!File.Exists(filePath)
                        || MessageBox.Show("类文件[" + this.txtEOName.Text + ".cs]已存在，是否要覆盖？", "确认", MessageBoxButtons.OKCancel) == DialogResult.OK) {
                        File.Delete(filePath);
                        FileStream fs = File.OpenWrite(filePath);
                        byte[] data = Encoding.GetEncoding(encode.Key).GetBytes(sbShadow.ToString());
                        fs.Write(data, 0, data.Length);
                        fs.Flush();
                        fs.Close();
                    }
                } else {
                    filePath = folderBrowserDialog1.SelectedPath + "/" + this.txtEOName.Text + ".cs";
                    if (!File.Exists(filePath)
                        || MessageBox.Show("类文件[" + this.txtEOName.Text + ".cs]已存在，是否要覆盖？", "确认", MessageBoxButtons.OKCancel) == DialogResult.OK) {
                        File.Delete(filePath);
                        FileStream fs = File.OpenWrite(filePath);

                        byte[] data = Encoding.GetEncoding(encode.Key).GetBytes(sbEO.ToString());
                        fs.Write(data, 0, data.Length);
                        fs.Flush();
                        fs.Close();
                    }

                }

                MySess.Mapping.Assembly = this.txtAssembly.Text;
                MySess.Mapping.Namespace = this.txtNamespace.Text;
                MySess.Mapping.LastSavePath = folderBrowserDialog1.SelectedPath;

                this.Close();
            }
        }

        private void cbxGenerator_SelectedIndexChanged(object sender, EventArgs e) {
            return;
            MyListItem li = (MyListItem)this.cbxGenerator.SelectedItem;
            if (!String.IsNullOrEmpty(li.Value)) {
                MessageBox.Show(li.Comment, "说明", MessageBoxButtons.OK);
            }
        }
    }
}
